Python Best Practice
Python 编码规范
- Python Coding Rule
 - PEP8
 - 遵从项目原有代码风格
 - 代码整洁优先级最高
 - 尽量使用 
key in dict或者dict.get(key)判断 dict 中是否存在key这个键或获取键key的value itertools包可以应付绝大部分对 list 类型数据的操作场景,遇到特殊的 list 类型数据操作需求时优先考虑使用itertools包,而非自行实现- 服务端一律使用 
time.time()获取 UTC 时间戳作为时间标识,在需要进行展示的地方使用对应方法转换为本时区的不同格式时间 - 通过截断逻辑避免缩进的出现。以下述代码为例:
 
def save_data_to_mongo(data):
    if data:
        check_data(data)
        format_data(data)
        extend_data(data)
        db.collection.insert(data)
更好的写法为:
def save_data_to_mongo(data):
    if not data:
        return
    check_data(data)
    format_data(data)
    extend_data(data)
    db.collection.insert(data)
- 函数拆分、接口设计原则优先考虑可读性,在出现性能问题时再考虑合并优化
 - 定义数值型常量时可以直接写清楚计算过程,解释器会帮忙将常量优化为计算结果
 
SECOND_ONE_WEEK = 604800
SECOND_ONE_WEEK = 7 * 24 * 3600    # better
try ... except Exception: ...本质上是异常处理,而非仅仅是异常捕获。稳定代码和非稳定代码要做出区分,应严格避免对大段代码的异常捕获,对异常的处理也应该尽可能细致,尽量避免不负责任的匿名 catch 的出现- Dict upsert
 
常规实现:
dict_uo2data = {}
if ip in dict_uo2data:
    dict_uo2data[ip].append(data)
else:
    dict_uo2data[ip] = [data]
更好的写法:
dict_uo2data = {}
dict_uo2data.setdefault(ip, []).append(data)
- 禁止使用 mutable 对象作为默认参数
 
错误示例一:
>>> def f(lst = []):
...     lst.append(1)
...     return lst
...
>>> f()
[1]
>>> f()
[1, 1]
错误示例二:
>>> import time
>>> def report(when=time.time()):
... return when
...
>>> report()
1500113234.487932
>>> report()
1500113234.487932
- 正确理解 
=和+=的区别 
>>> x = [1]
>>> print id(x)
4357132800
>>> x = x + [2]    # 指向一个新的对象
>>> print id(x) 
4357132728
>>> x = [1]
>>> print id(x)
4357132800
>>> x += [2]        # 修改原有对象
>>> print id(x)
4357132800
- 禁止使用乘法运算生成可变对象序列
 
In [5]: test = [[]] * 10
In [6]: test
Out[6]: [[], [], [], [], [], [], [], [], [], []]
In [7]: test[0].append(10)
In [8]: test
Out[8]: [[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]
In [9]: for i in test:
   ...:     print id(i)
4548762800
4548762800
4548762800
4548762800
4548762800
4548762800
4548762800
4548762800
4548762800
4548762800
- 禁止在访问列表的同时对列表中元素进行增删操作
 
In [11]: l = [1, 2, 4, 5]
In [12]: for i, v in enumerate(l):
    ...:     if v % 2 == 0:
    ...:         del l[i]
    ...:
In [13]: l
Out[13]: [1, 4, 5]    # 预期为 [1, 5]
- 禁止在 list comprehension 中使用 lambda 表达式
 
In [19]: for func in  [lambda x: i * x for i in range(5)]:
    ...:     print func(2)
8
8
8
8
8
问题产生根本原因在于 python 的属性查找规则。上述示例中 i 在闭包作用域,而 python 的闭包是 lazy binding,这意味着闭包中的值,是在内部函数被调用时查询到的。
在无法避免使用闭包时,可以通过传递默认参数将 i 置于本地作用域。
In [19]: for func in  [lambda x, i=i: i * x for i in range(5)]:
    ...:     print func(2)
- 禁止自行定义 
__del__函数,可能导致内存泄露。 
Circular references which are garbage are detected when the option cycle detector is enabled (it’s on by default), but can only be cleaned up if there are no Python-level del() methods involved.
- 迭代器只能被遍历一次
 
In [29]: test = iter([1, 2, 3, 4, 5])
In [30]: for i in range(2):
    ...:     for j in test:
    ...:         print i, j
0 1
0 2
0 3
0 4
0 5
In [31]: test.next()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-31-0743161fe2fe> in <module>()
----> 1 test.next()
StopIteration:
- 尽量使用 
get方法获取dict中对应 key 的 value 
test = {
    'list': [1, 2, 3, 4],
    'dict': {
        'key1': 1,
        'key2': 2
    },
    'int': 100,
    'string': 'test',
    'bool': True
}
test.get('list', [])
test.get('dict', {})
test.get('int', 0)
test.get('string', '')
test.get('bool', False)
- 函数返回值应为同一类型
 
错误示例:
In [54]: def func(arg):
    ...:     if arg:
    ...:         return [1, 2, 3, 4]
    ...:     else:
    ...:         return
    ...:
    ...: for i in func(False):
    ...:     print i
    ...:
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-54-eb27d4da633f> in <module>()
      5         return
      6
----> 7 for i in func(False):
      8     print i
      9
TypeError: 'NoneType' object is not iterable
正确示例:
In [55]: def func(arg):
    ...:     if arg:
    ...:         return [1, 2, 3, 4]
    ...:     else:
    ...:         return []
    ...:
    ...: for i in func(False):
    ...:     print i
    ...:
Tips
Alfred
- file saerch
 - web search
 - clipboard
 - snippets
 - workflow
 
Dash
autojump
ssh config
The known_hosts file lets the client authenticate the server, to check that it isn’t connecting to an impersonator. The authorized_keys file lets the server authenticate the user.
tmux
- https://github.com/dragonkid/tmux-config
 - zoom pane 
ctrl + z 
keychain
eval $(keychain -Q -q --agents ssh --eval ~/.ssh/id_rsa)
proxychains
mitmproxy
mitmproxy -p 9200 -R http://localhost:9201 -b 0.0.0.0 --no-mouse
virtualenvwrapper
vagrant
- vagrant scp
 - vagrant oh-my-zsh plugin
 
shell/zsh
alt + f/b: 前进/后退一个单词ctrl + f/b: 前进/后退一个字母ctrl + u/y: 清空/恢复当前输入ctrl + e: 移动到当前输入末尾ctrl + a: 移动到当前输入开头ctrl + '/": 为当前文本增加单/双引号ctrl + p/n: 查看上一条/下一条命令ctrl + r/ctrl + shift + r: 查找曾经输入过的命令,按多次查找下一个或上一个ctrl+xx: Move between the beginning of the line and the current position of the cursor. This allows you to pressctrl+xxto return to the start of the line, change something, and then pressctrl+xxto go back to your original cursor position. To use this shortcut, hold thectrlkey and tap thexkey twice.ctrl+d or Delete: Delete the character under the cursor.alt+d: Delete all characters after the cursor on the current line.alt + h: 命令输入到一半的时候需要查看 man 手册sudo插件: 按两次esc在命令的开头补齐 sudocolored-man-pages插件: man 手册高亮
Balsamiq
研发快速制作原型图
Pycharm
- ideavim(~/.ideavimrc 配置方式与 vim 相同)
 
This blog is under a CC BY-NC-SA 3.0 Unported License
Link to this article: https://dragonkid.github.io/2017/12/01/Python Best Practice/